package com.finance.system.support.utils;

import com.alibaba.fastjson.JSON;
import com.finance.system.support.bean.JwtToken;
import com.finance.system.support.exception.FinanceBusinessException;
import com.finance.system.user.entity.JwtPayload;
import com.finance.system.user.exception.AuthException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.UUID;

@Service
public class JwtTokenUtil {
    /**
     * 密钥
     */
    private static final String secret = "aaaaaaaa";

    private static final Long expiration = 12 * 3600 * 1000L;

    public static final String TOKEN_PREFIX = "Bearer ";


    /**
     *
     * 生成令牌
     * @param payload 用户信息
     * @return
     */
    public JwtToken generateToken(JwtPayload payload) {
        JwtToken jwtToken = new JwtToken();

        payload.setJti(UUID.randomUUID().toString())
                .setExp(new Date(System.currentTimeMillis() + expiration));
        jwtToken.setPayload(payload);
        return generateJwt(jwtToken);
    }

    /**
     * 解析令牌
     * @param token
     * @return JwtPayload
     * @throws AuthException.TokenNotExistException if token not exist
     * @throws AuthException.TokenExpiredException if token checked expired
     *
     */
    public JwtPayload parsePayload(String token) {
        if(StringUtils.isEmpty(token)) throw AuthException.tokenNotExistException();
        try {
            Claims claims = getClaimsFromToken(token);

            checkTokenOk(claims);

            JwtPayload payload = JSON.parseObject(JSON.toJSONString(claims), JwtPayload.class);
            return payload;
        }catch (FinanceBusinessException e) {
            throw e;
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 刷新令牌
     *
     * @param token 原令牌
     * @return 新令牌
     */
    public JwtToken refreshToken(String token) {
        JwtToken refreshedToken;
        try {
            Claims claims = getClaimsFromToken(token);
            JwtPayload payload = JSON.parseObject(JSON.toJSONString(claims), JwtPayload.class);
            refreshedToken = generateToken(payload);
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }

    private JwtToken generateJwt(JwtToken jwtToken) {
        jwtToken.setCreated(new Date());
        jwtToken.setJwt(TOKEN_PREFIX + Jwts.builder()
                .setPayload(JSONUtils.obj2json(jwtToken.getPayload()))
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact());
        return jwtToken;
    }


    private void checkTokenOk(Claims claims) {
        checkExpire(claims);
    }

    private void checkExpire(Claims claims) {
        Date expiration = claims.getExpiration();
        if(expiration.before(new Date())) throw AuthException.tokenExpiredException();
    }


    private Claims getClaimsFromToken(String token) {
        String jwt = getJwtFromToken(token);
        Claims claims;
        try {
            claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(jwt).getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }

    private String getJwtFromToken(String token) {
        return token.split(TOKEN_PREFIX)[1];
    }


}







